﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;

namespace CC.UI
{
    public static class Extenders
    {

        /// <summary>
        /// 将DtaGridView显示的内容变换成DataTable
        /// </summary>
        /// <param name="dataGridView"></param>
        /// <param name="titlField">使用哪个字段作为DataTable的列标题，默认为HeaderText</param>
        /// <returns></returns>
        public static DataTable ToDataTable(this DataGridView dataGridView, TitleFromDataGridView titlField= TitleFromDataGridView.ColumnHeaderText)
        {
            var dt = new DataTable();
            for (int c = 0; c < dataGridView.Columns.Count; c++)
            {
                switch (titlField)
                {
                    case TitleFromDataGridView.ColumnName:
                        dt.Columns.Add(dataGridView.Columns[c].Name);
                        break;
                    case TitleFromDataGridView.ColumnHeaderText:
                    default:
                        dt.Columns.Add(dataGridView.Columns[c].HeaderText);
                        break;
                    case TitleFromDataGridView.ColumnDataPropertyName:
                        dt.Columns.Add(dataGridView.Columns[c].DataPropertyName);
                        break;
                   
                }
                
            }

            var cell = new object[dataGridView.Columns.Count];
            foreach (DataGridViewRow dataGridViewRow in dataGridView.Rows)
            {
                for (int i = 0; i < dataGridViewRow.Cells.Count; i++)
                {
                    cell[i] = dataGridViewRow.Cells[i].Value;
                }
                dt.Rows.Add(cell);
            }
            return dt;
        }
        /// <summary>
        /// Chart自动调整X轴
        /// </summary>
        /// <param name="chart"></param>
        public static void AutoScaleX(this Chart chart)
        {
            foreach (ChartArea area in chart.ChartAreas)
            {
                int count = chart.Series.Count(s => s.ChartArea == area.Name);
                if (count <= 0) continue;
                var values = from serie in chart.Series.Where(s => s.ChartArea == area.Name)
                             select serie.Points.Max(p => p.XValue);
                if (values == null || values.Count() <= 0) continue;
                var xMax = values.Max();
                values = from serie in chart.Series.Where(s => s.ChartArea == area.Name)
                         select serie.Points.Min(p => p.XValue);
                var xMin = values.Min();
                area.AxisX.Minimum = Math.Floor(xMin);
                area.AxisX.Maximum = Math.Ceiling(xMax);
                area.AxisX.MajorGrid.Interval = (area.AxisX.Maximum - area.AxisX.Minimum) / 10;
                area.AxisX.MinorGrid.Enabled = false;
            }

        }
        /// <summary>
        /// Chart自动调整X轴
        /// </summary>
        /// <param name="chart"></param>
        /// <param name="range">显示范围，用于控制最小值为最大值-range。设置为0表示自适应最大最小 </param>
        public static void AutoScaleY(this Chart chart,double range=0)
        {
            foreach (ChartArea area in chart.ChartAreas)
            {
                var series = chart.Series.Where(s => s.ChartArea == area.Name);
                int count = series.Count();
                if (count <= 0) continue; //如果没有曲线，就跳过

                //找出每条曲线的最大值
                var values = from serie in series
                             select serie.Points.Max(p => p.YValues[0]);

                if (values == null || values.Count() <= 0) continue;
                var max = values.Max();
                double min;
                if(range>0)
                {
                    min = max - range;
                }
                else
                {
                    values = from serie in series
                             select serie.Points.Min(p => p.YValues.First());
                    min = values.Min();
                    if (max == min) min = max - 1f;
                }
              
                
                area.AxisY.Minimum = Math.Floor(min);
                area.AxisY.Maximum = Math.Ceiling(max);
                area.AxisY.MajorGrid.Interval = (area.AxisY.Maximum - area.AxisY.Minimum) / 10;
                area.AxisY.MinorGrid.Enabled = false;

            }

        }
        /// <summary>
        /// 获取当前鼠标位置对应绘图区的数据坐标
        /// </summary>
        /// <param name="chartArea">指定的绘图区</param>
        /// <param name="px">鼠标的x位置</param>
        /// <param name="py">鼠标的y位置</param>
        /// <returns>数据坐标，DataPoint类型</returns>
        public static DataPoint GetDataPointFromMousePosition(this ChartArea chartArea, int px, int py)
        {
           
            double x = 0, y = 0;
            if (chartArea != null)
            {
               
                if (!double.IsNaN(chartArea.AxisY.Minimum) && !double.IsNaN(chartArea.AxisY.Maximum))
                {
                    y = chartArea.AxisY.PixelPositionToValue(py);
                }
                if (!double.IsNaN(chartArea.AxisX.Minimum) && !double.IsNaN(chartArea.AxisX.Maximum))
                {
                    x = chartArea.AxisX.PixelPositionToValue(px);
                }
            }
            DataPoint point = new DataPoint(x, y);
            return point;
        }
        /// <summary>
        /// 高亮chart的一条曲线，ChartType.Line有效，其他不明
        /// </summary>
        /// <param name="chart"></param>
        /// <param name="series"></param>
        /// <param name="multiSelect"></param>
        /// <param name="highLightWidth"></param>
        /// <param name="normalWidth"></param>
        public static void HighlightSerie(this Chart chart, Series series, bool multiSelect = false, int highLightWidth = 3, int normalWidth = 1)
        {
            if (series == null) return;
            if (!multiSelect)
            {
                foreach (var serie in chart.Series.Where(s => s.ChartArea == series.ChartArea))
                {
                    serie.BorderWidth = normalWidth;
                }
            }
            series.BorderWidth = highLightWidth;
        }

        /// <summary>
        /// 为给定点增加频标
        /// </summary>
        /// <param name="chart"></param>
        /// <param name="location">chart中的坐标点，通常为鼠标事件中的Location</param>
        /// <param name="showMakerValue">是否要显示频标值,频标值通常为“P1:(2400,1.35)”</param>
        /// <param name="markerIndex">如果要显示频标值，需输入频标的索引，显示于频标值中</param>
        /// <returns></returns>
        public static DataPoint AddMarker(this Chart chart, Point location, bool showMakerValue, int markerIndex = 0)
        {
            var hit = chart.HitTest(location.X, location.Y);
            return AddMarker(chart, hit, showMakerValue, markerIndex);
        }
        /// <summary>
        /// MS Chart在鼠标处增加频标
        /// </summary>
        /// <param name="chart"></param>
        /// <param name="hit">根据坐标获取到的HitRestResult，一般为鼠标事件中的x,y坐标</param>
        /// <param name="showMakerValue">是否要显示频标值,频标值通常为“M1:(2400,1.35)”</param>
        /// <param name="markerIndex">如果要显示频标值，需输入频标的索引，显示于频标值中</param>
        /// <returns></returns>
        public static DataPoint AddMarker(this Chart chart, HitTestResult hit, bool showMakerValue, int markerIndex = 0)
        {

            DataPoint markerPoint = new DataPoint();
            if (hit.Series != null)
            {
                markerPoint = hit.Series.Points[hit.PointIndex];

                var xValue = hit.Series.Points[hit.PointIndex].XValue;
                var yValue = hit.Series.Points[hit.PointIndex].YValues.First();
                string text = "M" + markerIndex + ": (" + xValue + ", " + yValue.ToString("F2") + ")";

                AddVerticalLineAnotation(chart, -3, 3, hit.Series.Points[hit.PointIndex]);
                if (showMakerValue)
                    AddRectangleAnnotation(chart, text, hit.Series.Points[hit.PointIndex]);
            }
            return markerPoint;
        }
       
        private static void AddVerticalLineAnotation(Chart chart, int height, int width, DataPoint anchoPoint)
        {
            VerticalLineAnnotation annotation = new VerticalLineAnnotation
            {
                AnchorDataPoint = anchoPoint,
                Height = height,
                LineWidth = width,
                LineColor = Color.Red,
                StartCap = LineAnchorCapStyle.Arrow,
                EndCap = LineAnchorCapStyle.None,
                AllowMoving = false
            };
            chart.Annotations.Add(annotation);
        }
        private static void AddRectangleAnnotation(Chart chart, string text, DataPoint anchorPoint)
        {
            RectangleAnnotation annotation = new RectangleAnnotation
            {
                AnchorDataPoint = anchorPoint,
                AnchorOffsetY = 2,
                Text = text,
                ForeColor = Color.Red,
                Font = new Font("Arial", 10),
                LineWidth = 2,
                BackColor = Color.Transparent,
                LineDashStyle = ChartDashStyle.NotSet
            };
            chart.Annotations.Add(annotation);
        }
    }
}
